import java.util.ArrayList;
import java.util.List;

class CommandParser {

    private final List<Genome> genomes;

    public CommandParser(List<Genome> genomes) {
        this.genomes = genomes;
    }

    private static int parseIntHelper(String s, String expected) throws CommandFormatException {
        try {
            return Integer.parseInt(s);
        } catch (NumberFormatException e) {
            throw new CommandFormatException("Expected " + expected + ", found " + s);
        }
    }

    public Command parseCommand(String cmd) throws CommandFormatException {
        String[] tokens = cmd.split(" ");
        switch (tokens[0]) {
            case "insert": {
                if (tokens.length < 4) {
                    throw new CommandFormatException("insert should take at least 3 arguments");
                }
                int genomeIdx;
                int position;
                List<Integer> blocks;
                genomeIdx = parseIntHelper(tokens[1], "genome index");
                if (genomeIdx < 0 || genomeIdx >= genomes.size()) {
                    throw new CommandFormatException("Invalid genome index");
                }
                position = parseIntHelper(tokens[2], "position");
                blocks = new ArrayList<>();
                for (int i = 3; i < tokens.length; i++) {
                    blocks.add(parseIntHelper(tokens[i], "block"));
                }
                return new InsertCommand(genomeIdx, genomes.get(genomeIdx), position, blocks);
            }
            case "delete": {
                if (tokens.length != 4) {
                    throw new CommandFormatException("delete should take exactly 3 arguments");
                }
                int genomeIdx;
                int startBlock;
                int endBlock;
                genomeIdx = parseIntHelper(tokens[1], "genome index");
                if (genomeIdx < 0 || genomeIdx >= genomes.size()) {
                    throw new CommandFormatException("Invalid genome index");
                }
                startBlock = parseIntHelper(tokens[2], "start block");
                endBlock = parseIntHelper(tokens[3], "end block");
                return new DeleteCommand(genomeIdx, genomes.get(genomeIdx), startBlock, endBlock);
            }
            case "reverse": {
                if (tokens.length != 4) {
                    throw new CommandFormatException("reverse should take exactly 3 arguments");
                }
                int genomeIdx;
                int startBlock;
                int endBlock;
                genomeIdx = parseIntHelper(tokens[1], "genome index");
                if (genomeIdx < 0 || genomeIdx >= genomes.size()) {
                    throw new CommandFormatException("Invalid genome index");
                }
                startBlock = parseIntHelper(tokens[2], "start block");
                endBlock = parseIntHelper(tokens[3], "end block");
                return new ReverseCommand(genomeIdx, genomes.get(genomeIdx), startBlock, endBlock);
            }
            case "transposition": {
                if (tokens.length != 5) {
                    throw new CommandFormatException("transposition should take exactly 4 arguments");
                }
                int genomeIdx;
                int startBlock;
                int endBlock;
                int insertPosition;
                genomeIdx = parseIntHelper(tokens[1], "genome index");
                if (genomeIdx < 0 || genomeIdx >= genomes.size()) {
                    throw new CommandFormatException("Invalid genome index");
                }
                startBlock = parseIntHelper(tokens[2], "start block");
                endBlock = parseIntHelper(tokens[3], "end block");
                insertPosition = parseIntHelper(tokens[4], "insert position");
                return new TranspositionCommand(genomeIdx, genomes.get(genomeIdx), startBlock, endBlock, insertPosition);
            }
            default:
                throw new CommandFormatException("unknown command name \"" + cmd + "\"");
        }
    }
}
